# parser/utils.py (Ensure it exists with these functions)
import ast
from typing import Tuple, Optional, Union

def format_signature(node: Union[ast.FunctionDef, ast.AsyncFunctionDef]) -> Tuple[Optional[str], Optional[str]]:
    """Formats signature and extracts return type hint string."""
    try:
        signature_str = ast.unparse(node.args)
        return_hint_str = ast.unparse(node.returns) if node.returns else None
        return f"({signature_str})", return_hint_str
    except Exception as e:
        # Fallback or logging if unparse fails (unlikely for valid AST)
        print(f"Error parsing signature/return for {node.name}: {e}")
        return None, None

def get_docstring_from_node(node: Union[ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Module]) -> Optional[str]:
    """Safely extracts docstring."""
    return ast.get_docstring(node, clean=False)

def get_value_repr(node: Optional[ast.expr]) -> Optional[str]:
    """Tries to get a simple string representation for constant values."""
    if node is None:
        return None
    try:
        if isinstance(node, ast.Constant):
            # Simple constants (string, number, bool, None)
            return repr(node.value)
        elif isinstance(node, (ast.List, ast.Tuple, ast.Set)):
            # Basic sequence literals - potentially truncate if very long
            repr_str = ast.unparse(node)
            return repr_str if len(repr_str) < 100 else repr_str[:97] + "..."
        elif isinstance(node, ast.Dict):
            repr_str = ast.unparse(node)
            return repr_str if len(repr_str) < 100 else repr_str[:97] + "..."
        # Add more complex literals if needed (e.g., f-strings, joined strings)
        # For anything else, return None or a placeholder
        return None # Or potentially ast.unparse(node) for a best guess? Let's be conservative.
    except Exception:
        return None # Failed to get representation